﻿namespace Uber.WebUI.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Web.Mvc;
    using Core.Model;
    using log4net;
    using Core.Service;

    public class ListenerController : Controller
    {
        private readonly ILog log = LogManager.GetLogger(string.Empty);
        const string StrSandbox = "https://www.sandbox.paypal.com/cgi-bin/webscr";
        const string StrLive = "https://www.paypal.com/cgi-bin/webscr";
        private readonly IGoldBuys goldBuys;
        private readonly IEncryptor encryptor;

        public ListenerController(IGoldBuys goldBuys, IEncryptor encryptor)
        {
            this.goldBuys = goldBuys;
            this.encryptor = encryptor;
        }

        public ActionResult Index()
        {
            return Content(string.Empty);
        }

        public ActionResult Listen()
        {
            var formVals = new Dictionary<string, string> { { "cmd", "_notify-validate" } };

            var response = GetPayPalResponse(formVals, true);

            if (response == "VERIFIED")
            {
                while (true)
                {
                    try
                    {
                        //var business = Request["business"]; check to be mine
                        var transactionId = Request["txn_id"];
                        var amount = decimal.Parse(Request["mc_gross"], NumberStyles.AllowDecimalPoint, new CultureInfo("en-US"));
                        var quantity = Convert.ToInt32(Request["quantity"]);
                        var nid = Convert.ToInt64(encryptor.DecryptString(Request["custom"]));

                        if (goldBuys.Exists(transactionId))
                        {
                            log.Warn(string.Format("existing tid| tid: {0} ; amount: {1}; q: {2}; nid: {3}", transactionId, amount, quantity, nid));
                            break;
                        }

                        var result = goldBuys.Insert(new GoldBuy
                                                         {
                                                             Amount = amount,
                                                             Tid = transactionId,
                                                             Quantity = quantity,
                                                             Nid = nid,
                                                             Timp = DateTime.Now
                                                         });
                        if (!result)
                            log.Fatal(string.Format("wasn't saved| tid: {0} ; amount: {1}; q: {2}; nid: {3}; \n req amount: {4}; q: {5}; nid: {6}", 
                                transactionId, amount, quantity, nid, Request["mc_gross"], Request["quantity"], Request["custom"])); ;

                    }
                    catch (Exception ex)
                    {
                        log.Fatal(string.Format("error occured| tid: {0} ; req amount: {1}; q: {2}; nid: {3} \n" + ex.StackTrace, Request["txn_id"], Request["mc_gross"], Request["quantity"], Request["custom"]));
                    }
                    break;
                }
            }

            if (response == "INVALID")
            {
                log.Warn(string.Format("invalid request| tid: {0} ; req amount: {1}; q: {2}; nid: {3} ", Request["txn_id"], Request["mc_gross"], Request["quantity"], Request["custom"]));
            }
            else
            {
                log.Info(string.Format("request {0}| tid: {1} ; req amount: {2}; q: {3}; nid: {4} ", response, Request["txn_id"], Request["mc_gross"], Request["quantity"], Request["custom"]));
            }

            return Content("OK");
        }

        private string GetPayPalResponse(Dictionary<string, string> formVals, bool useSandbox)
        {
            var paypalUrl = useSandbox ? StrSandbox : StrLive;

            var req = (HttpWebRequest)WebRequest.Create(paypalUrl);
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            var param = Request.BinaryRead(Request.ContentLength);
            var strRequest = Encoding.ASCII.GetString(param);

            var sb = new StringBuilder();
            sb.Append(strRequest);

            foreach (var key in formVals.Keys)
            {
                sb.AppendFormat("&{0}={1}", key, formVals[key]);
            }
            strRequest += sb.ToString();
            req.ContentLength = strRequest.Length;

            string response;
            using (var streamOut = new StreamWriter(req.GetRequestStream(), Encoding.ASCII))
            {
                streamOut.Write(strRequest);
                streamOut.Close();
                using (var streamIn = new StreamReader(req.GetResponse().GetResponseStream()))
                {
                    response = streamIn.ReadToEnd();
                }
            }
            return response;
        }
    }
}